package Sdo.sftp;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import org.apache.log4j.Logger;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.ProxySOCKS4;
import com.jcraft.jsch.ProxySOCKS5;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import Sdo.terminalfx.helper.ThreadHelper;
import Sdo.pojo.PFile;
import Sdo.pojo.History;

public class JschTools {
	private static Logger logger = Logger.getLogger(JschTools.class);

	ObservableList<PFile> mChildrenList = FXCollections.observableArrayList();
	private static final int TIME_OUT = 30 * 60 * 1000; // 设置超时为5分钟
	Session session;
	ChannelSftp sftp = null;
	History history;

	// 创建文件夹
	public JschTools(History history) throws JSchException {
		this.history = history;
		connect(this.history);
	}

	private void connect(History history) throws JSchException {
		JSch jsch = new JSch();
		session = jsch.getSession(history.getUsername(), history.getIp().trim(), history.getPort());

		if (!session.isConnected()) {
			// 支持密钥的方式登陆，只需在jsch.getSession之前设置一下密钥的相关信息就可以了
			if (history.getPkey() != null && !"".equals(history.getPkey()) && !"选择密钥".equals(history.getPkey())) {
				if (history.getPassword() != null && !"".equals(history.getPassword())) {
					// 设置带口令的密钥
					jsch.addIdentity(history.getPkey(), history.getPassword());
				} else {
					// 设置不带口令的密钥
					jsch.addIdentity(history.getPkey());
				}
			} else {
				session.setPassword(history.getPassword());
			}

			session.setTimeout(TIME_OUT);
			session.setConfig("StrictHostKeyChecking", "no");
			if (history.getProxyType() != null) {
				if ("HTTP".equalsIgnoreCase(history.getProxyType())) {
					ProxyHTTP proxyHTTP = new ProxyHTTP(history.getProxyIp(), Integer.parseInt(history.getProxyPort()));
					if (history.getProxyUser() != null && !"".equals(history.getProxyUser())) {
						proxyHTTP.setUserPasswd(history.getProxyUser(), history.getProxyPassword());
					}
					session.setProxy(proxyHTTP);
				} else if ("SOCKS5".equalsIgnoreCase(history.getProxyType())) {
					ProxySOCKS5 ProxySOCKS5 = new ProxySOCKS5(history.getProxyIp(),
							Integer.parseInt(history.getProxyPort()));
					if (history.getProxyUser() != null && !"".equals(history.getProxyUser())) {
//						
//						logger.debug(history.getProxyUser());
//						logger.debug(history.getProxyPassword());

						ProxySOCKS5.setUserPasswd(history.getProxyUser(), history.getProxyPassword());
					}
					session.setProxy(ProxySOCKS5);
				} else if ("SOCKS4".equalsIgnoreCase(history.getProxyType())) {
					ProxySOCKS4 ProxySOCKS4 = new ProxySOCKS4(history.getProxyIp(),
							Integer.parseInt(history.getProxyPort()));
					if (history.getProxyUser() != null && !"".equals(history.getProxyUser())) {
						ProxySOCKS4.setUserPasswd(history.getProxyUser(), history.getProxyPassword());
					}
					session.setProxy(ProxySOCKS4);
				} else {
					// System.out.println("没有代理服务");
				}
			}
			session.connect();
			sftp = (ChannelSftp) session.openChannel("sftp");
			sftp.connect();
		}
	}

	@SuppressWarnings({ "unchecked" })
	public ObservableList<PFile> getHostPath(String dirPath) throws SftpException, JSchException, IOException {
		// connect(this.history);
		// TODO Auto-generated method stub
		if (!session.isConnected()) {
			System.out.println(">>>>>链接关闭");
		}else{
			System.out.println(">>>>>并未检测到链接关闭");
		}
		
		mChildrenList.clear();
		Vector<ChannelSftp.LsEntry> list = sftp.ls(dirPath);
		for (ChannelSftp.LsEntry entry : list) {

			PFile file = null;
			if (entry.getAttrs().isLink()) {

				// 如果是软链接就获取实际文件大小
				file = getFileInfo(dirPath + "/" + entry.getFilename().trim(), entry.getFilename().trim());

			} else {

				file = new PFile(entry.getAttrs().getUId(), entry.getAttrs().getGId(), entry.getFilename().trim(),
						entry.getAttrs().getAtimeString(), entry.getAttrs().getMtimeString(),
						String.valueOf(entry.getAttrs().getSize()), entry.getAttrs().isDir(),
						entry.getAttrs().getPermissionsString(),
						Imagev(entry.getAttrs().isDir(), entry.getAttrs().isLink(), entry.getFilename().trim()));

			}

			mChildrenList.add(file);
		}

		return mChildrenList;
	}

	public PFile getFileInfo(String path, String filename) throws SftpException, JSchException, IOException {
		// TODO Auto-generated method stub
		// connect(this.history);

		String rpath = sftp.realpath(path);

		SftpATTRS s = sftp.lstat(rpath);

		PFile file = new PFile(s.getUId(), s.getGId(), filename, s.getAtimeString(), s.getMtimeString(),
				String.valueOf(s.getSize()), s.isDir(), s.getPermissionsString(),
				Imagev(s.isDir(), s.isLink(), filename.trim()));

		return file;
	}

	@SuppressWarnings("unchecked")
	public void getfile(boolean isdir, String serverPath, String cfile, String localPath, ProgressBar pbar, Label label)
			throws SftpException, JSchException {

		// TODO Auto-generated method stub
		// 这里使用scp下载单个文件或者文件夹速度较快
		if (isdir) {

			serverPath = serverPath + "/" + cfile;
			localPath = localPath + "/" + cfile;

			java.io.File f = new java.io.File(localPath);
			if (!f.exists()) {
				f.mkdirs();
			}

			Vector<ChannelSftp.LsEntry> list = sftp.ls(serverPath);
			for (ChannelSftp.LsEntry entry : list) {

				if (entry.getFilename().trim().equals(".") || entry.getFilename().trim().equals("..")) {

				} else {
					getfile(entry.getAttrs().isDir(), serverPath, entry.getFilename().trim(), localPath, pbar, label);
				}

			}

		} else {
			SftpATTRS attrs = sftp.lstat(sftp.realpath(serverPath + "/" + cfile));

			// System.out.println(">>>>>>>>实际文件大小>>>>>>>"+attrs.getSize());

			sftp.get(serverPath + "/" + cfile, localPath + "/" + cfile,
					new FileSftpProgressMonitor(attrs.getSize(), cfile, "get", pbar, label));

		}

	}

	public void mv(String oldPath, String newPath, Label label) throws SftpException, JSchException {
		// TODO Auto-generated method stub

		if (sftp.lstat(newPath).isDir()) {
			// sftp.mv(oldPath, newPath);
			// connect(history);

			String command = "mv " + oldPath + " " + newPath;
			logger.debug(command);
			ChannelExec channel = (ChannelExec) session.openChannel("exec");
			channel.setCommand(command);
//			channel.connect();
//			channel.disconnect();

		} else {

			ThreadHelper.runActionLater(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					label.setManaged(true);
					label.setVisible(true);
					label.setText("移动操作失败,不能移动到非文件夹里去");

					label.setAlignment(Pos.CENTER);
					label.setTextFill(Color.web("#ff0000", 0.8));

					Timer t = new Timer();
					t.schedule(new TimerTask() {

						@Override
						public void run() {
							// TODO Auto-generated method stub
							label.setManaged(false);
							label.setVisible(false);
							// System.out.println("自动消失");
							t.cancel();
						}
					}, 5000, 1);

				}
			});

		}

	}

	public void putfile(File file, String remoteTargetDirectory, ProgressBar pbar, Label label)
			throws SftpException, FileNotFoundException, JSchException {
		// connect(history);
		ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
		channelSftp.connect();
		if (file.isDirectory()) {
			// System.out.println(">>>22>>"+remoteTargetDirectory);
			if (remoteTargetDirectory.contains("~")) {
				if ("~".equals(remoteTargetDirectory.trim())) {
					remoteTargetDirectory = sftp.pwd();
				} else {
					remoteTargetDirectory = sftp.pwd() + "/" + remoteTargetDirectory.replace("~", "");
				}

			}

			remoteTargetDirectory = sftp.realpath(remoteTargetDirectory);

			sftp.cd(remoteTargetDirectory);
			remoteTargetDirectory = remoteTargetDirectory + "/" + file.getName();

			channelSftp.mkdir(remoteTargetDirectory);

			File files = new File(file.getPath());
			File[] tempList = files.listFiles();

			for (int i = 0; i < tempList.length; i++) {
				putfile(tempList[i], remoteTargetDirectory, pbar, label);
			}
		} else {
			channelSftp.cd(remoteTargetDirectory);
			channelSftp.put(file.getPath(), remoteTargetDirectory,
					new FileSftpProgressMonitor(file.length(), file.getName(), "put", pbar, label));

		}
		channelSftp.exit();
	}

	public void Rename(String oldPath, String newPath) throws SftpException, JSchException {

		// 创建文件夹
		sftp.rename(oldPath, newPath);

	}

	public void mkDir(String serverPath) throws SftpException, JSchException {

		// 创建文件夹
		sftp.mkdir(serverPath);

	}

	public static ArrayList<String> getFiles(String path) {
		ArrayList<String> files = new ArrayList<String>();
		File file = new File(path);
		File[] tempList = file.listFiles();

		for (int i = 0; i < tempList.length; i++) {
			if (tempList[i].isFile()) {
				files.add(tempList[i].toString());
			}
			if (tempList[i].isDirectory()) {
				files.add(tempList[i].toString());
				getFiles(tempList[i].toString());
			}
		}
		return files;
	}

	public void rmfile(String serverPath, ObservableList<PFile> cfile) throws JSchException {
		// 直接命令删除文件夹,不论是不是为空

		String cmdstr = "rm -rf";
		for (PFile pFile : cfile) {
			cmdstr = cmdstr + " " + serverPath + "/" + pFile.getFilename();
		}
		ChannelExec channel = (ChannelExec) session.openChannel("exec");
		channel.setCommand(cmdstr);
//		channel.connect();
//		channel.disconnect();

	}

	public void close() {
		sftp.disconnect();
		session.disconnect();
	}

	public ImageView Imagev(Boolean b, Boolean islink, String s) throws IOException {

		ImageView image = new ImageView(new Image("/icon/folder-icon-1.png"));
		if (s.equals(".")) {

			image = new ImageView(new Image("/icon/display-icon.png"));

		} else if (s.equals("..")) {
			image = new ImageView(new Image("/icon/folder-icon-1.png"));

		} else {
			if (b) {
				image = new ImageView(new Image("/icon/folder-icon-2.png"));

			} else {

				if (islink) {
					image = new ImageView(new Image("/icon/no-icon.png"));

				} else {

					if (s.endsWith(".sh") || s.endsWith(".py") || s.endsWith(".cmd") || s.endsWith(".php")
							|| s.endsWith(".js") || s.endsWith(".html") || s.endsWith("vue") || s.endsWith(".htm")
							|| s.endsWith(".asp") || s.endsWith(".jsp") || s.endsWith(".aspx") || s.endsWith(".java")
							|| s.endsWith(".cs")) {
						image = new ImageView(new Image("/icon/code.png"));
					} else if (s.endsWith(".zip") || s.endsWith(".rar") || s.endsWith(".tar") || s.endsWith(".7z")
							|| s.endsWith(".gz") || s.endsWith(".bzip2")) {
						image = new ImageView(new Image("/icon/zip.png"));
					} else if (s.endsWith(".doc") || s.endsWith(".txt") || s.endsWith(".docx") || s.endsWith(".md")) {
						image = new ImageView(new Image("/icon/doc.png"));
					} else if (s.endsWith(".gif") || s.endsWith(".png") || s.endsWith(".jpg") || s.endsWith(".jpeg")) {
						image = new ImageView(new Image("/icon/image-icon.png"));
					} else if (s.endsWith(".mp3") || s.endsWith(".mov") || s.endsWith(".avi") || s.endsWith(".mpg")
							|| s.endsWith(".mpg") || s.endsWith(".mpeg") || s.endsWith(".dat") || s.endsWith(".mp4")
							|| s.endsWith(".3gp") || s.endsWith(".mov") || s.endsWith(".rm") || s.endsWith(".rmvb")
							|| s.endsWith(".wmv") || s.endsWith(".asx")) {

						image = new ImageView(new Image("/icon/video-icon.png"));
					} else {
						image = new ImageView(new Image("/icon/unknown-icon.png"));
					}

				}

			}

		}

		return image;
	}

}

/**
 * 监控文件传输
 */
class FileSftpProgressMonitor extends TimerTask implements SftpProgressMonitor {

	private long progressInterval = 1000; // 默认间隔时候为5秒

	private boolean isEnd = false; // 记录传输是否停止

	private long transfered; // 记录已传输的数据总大小

	private long fileSize; // 记录文件总大小

	private Timer timer; // 定时器对象
	private String filename; // 文件名
	private String putorget;
	private ProgressBar pbar;
	private boolean isScheduled = false; // 记录是否已启动timer定时器
	Label systeminfo;

	private NumberFormat df = NumberFormat.getInstance(); // 格式化

	public FileSftpProgressMonitor(long fileSize, String filename, String putorget, ProgressBar pbar, Label label) {
		this.fileSize = fileSize;
		this.filename = filename;
		this.putorget = putorget;
		this.pbar = pbar;
		this.systeminfo = label;
	}

	@Override
	public void run() {
		if (!isEnd()) {
			long transfered = getTransfered();
			if (transfered != fileSize) {

				System.out.println("Current transfered: " + transfered + " bytes");
				sendProgressMessage(transfered, filename, putorget, pbar);
			} else {
				System.out.println("transfered end.");
				setIsEnd(true);
			}
		} else {
			ThreadHelper.runActionLater(() -> {
				// TODO Auto-generated method stub
				systeminfo.setVisible(true);
				systeminfo.setManaged(true);
				systeminfo.setAlignment(Pos.CENTER);
				systeminfo.setTextFill(Color.web("#ff0000", 0.8));
				pbar.setVisible(false);
				pbar.setManaged(false);
				// 更新JavaFX的主线程的代码放在此处
				if (putorget.equals("get")) {
					systeminfo.setText(filename + ">>>>>>>>下载完成！");

				} else {
					systeminfo.setText(filename + "<<<<<<<<上传完成！");
				}

				Timer t = new Timer();
				t.schedule(new TimerTask() {

					@Override
					public void run() {
						// TODO Auto-generated method stub
						systeminfo.setManaged(false);
						systeminfo.setVisible(false);
						// System.out.println("自动消失");
						t.cancel();
					}
				}, 10000, 1);

			});
			// System.out.println("Transfering done. Cancel timer.");
			stop(); // 若是传输停止，停止timer记时器

		}
	}

	/**
	 * 定时器关闭
	 */
	public void stop() {

		System.out.println("Try to stop progress monitor.");
		if (timer != null) {
			timer.cancel();
			timer.purge();
			timer = null;
			isScheduled = false;
		}

		System.out.println("Progress monitor stoped.");

	}

	/**
	 * 定时器启动
	 */
	public void start() {
		System.out.println("Try to start progress monitor.");
		if (timer == null) {
			timer = new Timer();
		}
		timer.schedule(this, 1000, progressInterval);
		isScheduled = true;
		System.out.println("Progress monitor started.");

	}

	/**
	 * 传输进度
	 * 
	 * @param transfered
	 */
	private void sendProgressMessage(long transfered, String filename, String putorget, ProgressBar pbar) {
		if (fileSize != 0) {
			double d = transfered / (double) fileSize;

			pbar.setProgress(d);
			System.out.println(">>>>>>>>>>" + transfered);
			System.out.println(">>>>>>>>>>" + fileSize);

			System.out.println("File" + filename + ",Sending progress message: " + df.format(d) + "%");
		} else {

			System.out.println("Sending progress message: " + transfered);
		}
	}

	@Override
	public void init(int i, String s, String s1, long l) {

		System.out.println("transfering start.");

		ThreadHelper.runActionLater(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				pbar.setVisible(true);
				pbar.setManaged(true);
				pbar.setProgress(0);

			}
		});
	}

	@Override
	public boolean count(long l) {
		if (isEnd()) {
			return false;
		}
		if (!getIsScheduled()) {
			start();
		}
		add(l);
		return true;
	}

	@Override
	public void end() {
		setIsEnd(false);

		System.out.println("transfering end.");

	}

	private synchronized void add(long count) {
		transfered = transfered + count;
	}

	public synchronized boolean isEnd() {
		return isEnd;
	}

	public synchronized void setIsEnd(boolean isEnd) {
		this.isEnd = isEnd;
	}

	public synchronized long getTransfered() {
		return transfered;
	}

	public synchronized void setTransfered(long transfered) {
		this.transfered = transfered;
	}

	public synchronized boolean getIsScheduled() {
		return isScheduled;
	}

	public synchronized void setIsScheduled(boolean isScheduled) {
		this.isScheduled = isScheduled;
	}

}